/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package cn.ac.iie.di.zhihu.gkfb.handler;

import cn.ac.iie.di.commons.httpserver.framework.handler.HandlerI;
import cn.ac.iie.di.zhihu.gkfb.common.RuntimeEnv;
//import static cn.ac.iie.di.zhihu.gkfb.common.RuntimeEnv.countRequest;
import com.alibaba.fastjson.JSONObject;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.zip.GZIPInputStream;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.eclipse.jetty.server.Request;

/**
 *
 * @author Administrator
 */
public class GKFeedBackHandler implements HandlerI {

    static Logger logger = Logger.getLogger(GKFeedBackHandler.class.getName());

    @Override
    public void init() throws Exception {
    }

    @Override
    public void execute(Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws Exception {

        ServletOutputStream out = response.getOutputStream();
        BufferedOutputStream bos = new BufferedOutputStream(out);
        try {
            long startTime = System.nanoTime();
            String reqID = String.valueOf(startTime);
            JSONObject tableInfo = null;
            StringBuilder sb = new StringBuilder("");
            String result = "";
            //从流中获取请求
            try {
                baseRequest.setHandled(true);
                //获取客户端ip，端口
                String remoteHost = baseRequest.getRemoteAddr();
                int remotePort = baseRequest.getRemotePort();
                logger.info("receive request from " + remoteHost + ":" + remotePort + " and assigned id " + reqID);
                ServletInputStream servletInputStream = null;
                byte[] req = null;
                boolean flag = false;
                try {
                    logger.debug("req " + reqID + ":retriving bussisness data for request  ...");
                    //获取客户端的二进制数据
                    servletInputStream = baseRequest.getInputStream();
                    ByteArrayOutputStream bout = new ByteArrayOutputStream();
                    byte[] b = new byte[4096];
                    int i = 0;
                    while ((i = servletInputStream.read(b, 0, 4096)) > 0) {
                        bout.write(b, 0, i);
                    }
                    req = bout.toByteArray();
//                    logger.debug(countRequest.incrementAndGet() + "==========" + "req " + reqID + ":length of bussisness data is " + req.length);
                    flag = true;
                } catch (Exception ex) {
                    String errInfo = "req " + reqID + ":retrive bussiness data unsuccessfully for " + ex.getMessage().replace("\"", "\'");
                    logger.error(errInfo, ex);
                    sb.append("{\"total_accessed_num\": ").append("").append(",\"success_accessed_num\":").append("").append(",\"ret_code\":").append("-1").append(",\"err_msg\":").append("\"").append(errInfo).append("\"").append("}");
                    result = sb.toString();
                } finally {
                    try {
                        servletInputStream.close();
                    } catch (Exception ex) {
                        logger.error(ex, ex);
                    }
                }
                //判断是否为空
                if (flag) {
                    if (req == null || req.length == 0) {
                        String warnInfo = "req " + reqID + " - retrive bussiness data unsuccessfully for content is empty";
                        logger.error(warnInfo);
                        sb.append("{\"total_accessed_num\": ").append("").append(",\"success_accessed_num\":").append("").append(",\"ret_code\":").append("-1").append(",\"err_msg\":").append("\"").append(warnInfo).append("\"").append("}");
                        result = sb.toString();
                    } else {
                        byte[] jsonBytes = unGZip(req);
                        String json = new String(jsonBytes, "UTF-8");
                        boolean jsonFlag = false;
                        try {
                            //将解压的数据转换为json对象
                            tableInfo = JSONObject.parseObject(json);
                            jsonFlag = true;
                        } catch (Exception e) {
                            String errInfo = "req " + reqID + " - internal error for sending data unsuccessfully for " + e.getMessage().replace("\"", "\'");
                            logger.error(errInfo + "\n" + json, e);
                            sb.append("{\"total_accessed_num\": ").append("").append(",\"success_accessed_num\":").append("").append(",\"ret_code\":").append("-1").append(",\"err_msg\":").append("\"").append(errInfo).append("\"").append("}");
                            result = sb.toString();
                        }
                        if (jsonFlag) {

//                            logger.info("get one msg , and the msg is \n" + tableInfo);

                            long acceptTime = System.currentTimeMillis() / 1000;
                            tableInfo.put("accept_time", acceptTime);
//                            logger.info("get one json , the dataType : " + " , the total_pushed_num : " + tableInfo.getString("total_pushed_num") + " , WEBSITEID : " + " from " + remoteHost + ":" + remotePort + " and assigned id " + reqID);
                            //拼接返回值格式
                            sb.append("{\"total_accessed_num\": ").append(tableInfo.getString("total_pushed_num")).append(",\"success_accessed_num\":").append(tableInfo.getString("total_pushed_num")).append(",\"ret_code\":").append("0").append(",\"err_msg\":").append("\"\"").append("}");
                            result = sb.toString();

                            //将数据放回缓冲buff，后续处理
                            while (true) {
                                if (RuntimeEnv.dataPool.offer(tableInfo.toString().replaceAll("\n", ""))) {
                                    break;
                                }
                                Thread.sleep(10);
                            }
                        }
                    }
                }
                response.setStatus(HttpServletResponse.SC_OK);
                InputStream inputStream = new ByteArrayInputStream(result.getBytes("UTF-8"));
                //返回指令结果,指令结果也是经过加密的吗
                byte[] bytesContent = new byte[1024 * 2];
                int bytesReadIn = 0;
                while ((bytesReadIn = inputStream.read(bytesContent, 0, 1024 * 2)) > 0) {
                    bos.write(bytesContent, 0, bytesReadIn);
                }
                bos.flush();
                bos.close();
//                logger.info("send response ok");
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
                String errInfo = "req " + reqID + " - internal error for sending data unsuccessfully for " + e.getMessage().replace("\"", "\'");
                response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                sb.append("{\"total_accessed_num\": ").append("").append(",\"success_accessed_num\":").append("").append(",\"ret_code\":").append("-1").append(",\"err_msg\":").append("\"").append(errInfo).append("\"").append("}");
                result = sb.toString();
                PrintWriter writer = response.getWriter();
                writer.println(result);

//                writer.flush();
//                writer.close();
            } finally {
                long endTime = System.nanoTime();
                logger.info("dispose req " + reqID + " consume " + (endTime - startTime) / (1000 * 1000) + " ms");
            }
        } catch (IOException ex) {
            logger.error(ex.getMessage(), ex);
        } finally {
//            System.exit(1);
        }

    }

    public static byte[] unGZip(byte[] data) throws IOException {
        byte[] b;

        ByteArrayInputStream bis = new ByteArrayInputStream(data);
        GZIPInputStream gzip = new GZIPInputStream(bis);
        byte[] buf = new byte[1024];
        int num = -1;
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        while ((num = gzip.read(buf, 0, buf.length)) != -1) {
            baos.write(buf, 0, num);
        }
        b = baos.toByteArray();
        baos.flush();
        baos.close();
        gzip.close();
        bis.close();
        return b;
    }
}
